import React, { useRef, useCallback, useState, useEffect } from 'react';
import {
    ReactFlow,
    ReactFlowProvider,
    useNodesState,
    Controls,
    useReactFlow,
    Background,
    Panel,
    MiniMap,
    OnNodesChange,
} from '@xyflow/react';
import '@xyflow/react/dist/style.css';
import { DnDProvider, useDnD } from './DnDContext';
import { Sidebar } from './Sidebar';
import './index.css';
import Ruler from '@scena/react-ruler';
import { getAllPdfNodeType, getPdfNodeType } from './Sidebar/design';
import { PdfDocument, PdfNodeProps } from './components';
import { pdf } from '@react-pdf/renderer';
import { PropertiesPanel } from './PropertiesPanel';
import { Button, Space, Splitter } from 'antd';
import { PdfTemplateUtil, UnitUtil } from './utils';
const flowKey = 'example-flow';
const getId = () => `dndnode_${new Date().getTime()}`;
const initialNodes: PdfNodeProps[] = [
    {
        id: 'dndnode_1',
        type: 'PdfText',
        data: { label: 'Text' },
        position: { x: 100, y: 100 },
        height: 30,
        width: 100,
    },
];

const DnDFlow = () => {
    const { updateNode, getNode } = useReactFlow();
    const [nodes, setNodes, flowOnNodesChange] = useNodesState<PdfNodeProps>(initialNodes);
    const [selectedNode, setSelectedNode] = useState<PdfNodeProps>(undefined);
    const { screenToFlowPosition } = useReactFlow();
    const [type] = useDnD();
    const [rfInstance, setRfInstance] = useState(null);
    const { setViewport } = useReactFlow();
    const [scrollPos, setScrollPos] = useState({ x: 0, y: 0 });
    const [zoom, setZoom] = useState(1);
    const containerRef = useRef<HTMLDivElement>(null);
    const handleExport = async () => {
        const id = new Date().getTime();
        const template = getTemplate();
        let newTemplate = PdfTemplateUtil.toPt(template);
        newTemplate = await PdfDocument.loadData(newTemplate);
        const blob = await pdf(<PdfDocument unit='pt' key={id} nodes={newTemplate.nodes} />).toBlob();
        const url = URL.createObjectURL(blob);
        window.open(url, id);
    };
    useEffect(() => {
        setViewport({ x: 0, y: 0, zoom: 1 });//标尺转单位:pxTomm
    }, [])
    const onNodesChange: OnNodesChange<PdfNodeProps> = (changes) => {
        flowOnNodesChange(changes);
        if (selectedNode) {
            setTimeout(() => {
                const node = getNode(selectedNode.id)
                if (node) {
                    console.debug("onNodesChange", node, changes);
                    setSelectedNode(node);
                }
            }, 5)

        }
    }
    // 同步滚动位置
    useEffect(() => {
        const handler = () => {
            if (containerRef.current) {
                setScrollPos({
                    x: containerRef.current.scrollLeft,
                    y: containerRef.current.scrollTop
                });
            }
        };
        containerRef.current?.addEventListener('scroll', handler);
        return () => containerRef.current?.removeEventListener('scroll', handler);
    }, []);
    const onDragOver = useCallback((event) => {
        event.preventDefault();
        event.dataTransfer.dropEffect = 'move';
    }, []);

    const onDrop = useCallback(
        (event) => {
            event.preventDefault();
            // check if the dropped element is valid
            if (!type) {
                return;
            }
            const nodeType = getPdfNodeType(type);
            // project was renamed to screenToFlowPosition
            // and you don't need to subtract the reactFlowBounds.left/top anymore
            // details: https://reactflow.dev/whats-new/2023-11-10
            const position = screenToFlowPosition({
                x: event.clientX,
                y: event.clientY,
            });
            const newNode = {
                ...nodeType.defaultProps,
                width: nodeType.defaultProps.width,
                height: nodeType.defaultProps.height,
                id: getId(),
                type,
                position,
                data: { label: `${type} node` },
            };
            setNodes((nds) => nds.concat(newNode));
        },
        [screenToFlowPosition, type],
    );
    const getTemplate = () => {
        const flow = rfInstance.toObject();
        const printTemplate = { ...flow, unit: UnitUtil.getUnit() }
        return printTemplate;
    }
    const onSave = useCallback(() => {
        if (rfInstance) {
            const printTemplate = getTemplate();
            localStorage.setItem(flowKey, JSON.stringify(printTemplate));
        }
    }, [rfInstance]);

    const onRestore = useCallback(() => {
        const restoreFlow = async () => {
            const flow = JSON.parse(localStorage.getItem(flowKey));
            if (flow) {
                // const { x = 0, y = 0, zoom = 1 } = flow.viewport;
                setNodes(flow.nodes || []);
            }
        };
        restoreFlow();
    }, [setNodes, setViewport]);

    return <Splitter style={{ height: "100%", boxShadow: '0 0 10px rgba(0, 0, 0, 0.1)' }}>
        <Splitter.Panel defaultSize="20%" collapsible>
            <Sidebar></Sidebar>
        </Splitter.Panel>
        <Splitter.Panel collapsible={{ start: true }}>
            <div
                className="dndflow"
                style={{
                    display: "flex",
                    flexDirection: "column",
                    overflow: "hidden",
                    height: "100%"
                }}
            >

                {/* px水平标尺 */}
                <Ruler
                    type="horizontal"
                    zoom={zoom}
                    unit={25}
                    scrollPos={-scrollPos.x}
                    style={{ height: 30, marginLeft: 60, }}
                />
                {/* mm水平标尺 */}
                <Ruler
                    type="horizontal"
                    zoom={UnitUtil.mmToPx(zoom)} //放大和px标尺对其
                    unit={10}//10毫米
                    scrollPos={UnitUtil.pxToMm(-scrollPos.x)}//移动 转mm
                    style={{ height: 30, marginLeft: 60, }}
                />
                <div style={{ display: "flex", flex: 1 }}>
                    {/* px垂直标尺 */}
                    <Ruler
                        type="vertical"
                        zoom={zoom}
                        unit={25}
                        scrollPos={-scrollPos.y}
                        style={{ width: 30 }}
                    />
                    {/* mm垂直标尺 */}
                    <Ruler
                        type="vertical"
                        zoom={UnitUtil.mmToPx(zoom)} //放大和px标尺对其
                        unit={10}//10毫米
                        scrollPos={UnitUtil.pxToMm(-scrollPos.y)}//移动 转mm
                        style={{ width: 30, }}
                    />
                    {/* React Flow 画布 */}
                    <div
                        className="reactflow-wrapper"
                        ref={containerRef}
                        style={{
                            flex: 1,
                            overflow: "auto",
                            position: "relative",
                            border: "1px solid #ccc",
                        }}
                    >
                        <ReactFlow
                            // ref={reactFlowRef}
                            onNodeClick={(_, node) => setSelectedNode(node)}
                            nodes={nodes}
                            onNodesChange={onNodesChange}
                            onDrop={onDrop}
                            onDragOver={onDragOver}
                            nodeTypes={getAllPdfNodeType()}
                            onInit={setRfInstance}
                            panOnDrag={true}
                            onMove={(_, viewport) => {
                                setZoom(viewport.zoom);
                                //标尺自身会缩放：恢复缩放前的pos(x,y)
                                setScrollPos({ x: viewport.x / viewport.zoom, y: viewport.y / viewport.zoom });
                            }}
                            snapToGrid={true}
                            snapGrid={[1, 1]}
                            // fitView
                            // fitViewOptions={{ padding: 2 }}
                            // style={{ backgroundColor: "#F7F9FB" }}
                            style={{ width: "2000px", height: "2000px" }}
                        >
                            <MiniMap />
                            <Controls />
                            <Background />
                            <Panel position="bottom-right">
                                <Space>
                                    <Button onClick={onSave}>Save</Button>
                                    <Button onClick={onRestore}>Restore</Button>
                                    <Button onClick={handleExport}>ExportPdf</Button>
                                </Space>
                            </Panel>
                        </ReactFlow>
                    </div>
                </div>
            </div >
        </Splitter.Panel>
        <Splitter.Panel defaultSize="300">
            <PropertiesPanel updateNode={updateNode} node={selectedNode}></PropertiesPanel>
        </Splitter.Panel>
    </Splitter>
};
const PrintDesign = () => {
    useEffect(() => {
        const reactFlowNode = document.querySelector('a[href="https://reactflow.dev"]');
        reactFlowNode?.remove();
    }, [])
    return <>
        <ReactFlowProvider>
            <DnDProvider>
                <DnDFlow />
            </DnDProvider>
        </ReactFlowProvider>
    </>
}
export default PrintDesign;